using System;
using System.Data;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Configuration;
using Microsoft.Win32;
using System.Text;
using System.Runtime.InteropServices;

using BO = PHSRAG.Insight21.BusinessObjects;
using DataAccess = PHSRAG.Utility.DataAccess;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using Utility = PHSRAG.Utility;
using Helper = PHSRAG.WebControls.Helper;
using System.Collections;
using PHSRAG.SharePointUtility;
using System.Collections.Generic;


namespace PHSRAG.Insight21.CDS
{
	/// <summary>
	/// Document class abstracts the notion of an electronic attachment. This class saves attachments/files in the database.
	/// Allows files to be scanned for viruses. The virus scanning software used is Trend software's SysClean command line utility.
	/// </summary>
	public class Document : BO.SmartBusinessObject, ICloneable
	{
		#region InterOp
		/// <summary>
		/// The Document object invokes the configured virus scanner as part of its step in saving the document in the
		/// database. This action is carried out in a separate process so as not to block the main thread which invoked
		/// the action. It therefore becomes imperative to use short path names and since .NET does not provide a method
		/// to convert a long path to a short path, we simply use InterOp to invoke the Win32 API GetShortPathName().
		/// </summary>
		/// <param name="longPath">Long path (which may contain embedded white-space)</param>
		/// <param name="shortPath">Short path equivalent of the long path</param>
		/// <param name="bufferSize">Size of the short-path buffer</param>
		/// <returns>Actual length of the short path</returns>
		[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
		public static extern int GetShortPathName(
			[MarshalAs(UnmanagedType.LPTStr)] string longPath, 
			[MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath, 
			[MarshalAs(UnmanagedType.U4)] int bufferSize); 
		#endregion

		/// <summary>
		/// Columns of Document Table
		/// </summary>
		public enum DocumentDatabaseTableColumns
		{
			Id,  
			Name, 
			DateCreated, 
			Blob, 
			MarkForRemoval 
		}


		#region Constants
		private const string DocumentKey = "Document_EE55E7B3-DA44-4fc3-869A-C2A568E1E4CE";
		private const string DocumentDatabaseTableName = "Document";
		private const string ColumnNameId = "Id";
		private const string ColumnNameName = "Name";
		private const string ColumnNameDateCreated = "DateCreated";
		private const string ColumnNameBlob = "Blob";
		private const string ColumnNameMarkForRemoval = "MarkForRemoval";
		private const string ColumnNameIsConvertedToPdf = "IsConvertedToPdf";
		public const string FilePathKey = "FilePath";

		/// <summary>
		/// A string that marks the completion of virus scanning. This is part of the output generated by the scanning tool
		/// </summary>
		private const string ScanComplete = "1 files have been checked";

		/// <summary>
		/// A string that indicates that the file scanned was clean. This is part of the output generated by the scanning tool
		/// </summary>
		private const string NoViruses = "No file-type viruses found";

		/// <summary>
		/// The configuration key that holds the name and path of the command line utility that scans files for viruses
		/// </summary>
		private const string ScanToolFilePathNameKey = "ScanToolFilePath";

		/// <summary>
		/// The maximum time allowed for scanning a file
		/// </summary>
		private const string ScanningTimeoutKey = "ScanTimeout";
		#endregion

		#region Instance Variables
		private string name;
		private DateTime dateCreated;
		private byte[] blob;
        private byte[] pdfBlob;
		private bool markForRemoval;
		private bool isConvertedToPdf;
        private bool isSharePointDocument;
        private Hashtable metadata;
        private string folderHierarchy;
        private string filePath;
        private bool clone;
		#endregion

		#region Class Variables
		private static bool		enableVirusScanning = false;
		private static string	virusScanner;
		private static string	virusScannerSuccessMessage;
		private static int		virusScannerTimeout = 0;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new Document object based on the Cache Policy passed in as a parameter. 
		/// All the instance variables will be set to their default values.
		/// </summary>
		/// <param name="cachePolicy">Cache Policy which specifies where the Document object should be cached</param>
		public Document(ICachePolicy cachePolicy) : base(cachePolicy)
		{
		}

		/// <summary>
		/// Constructs a new Document object based on the Cache Policy passed in as a parameter. 
		/// All the instance variables will be set to the corresponding values specified in the Data Row 
		/// </summary>
		/// <param name="cachePolicy">Cache Policy which specifies where the Document object should be cached</param>
		/// <param name="dataRow">DataRow with columns in the order specified in DocumentDatabaseTableColumns</param>
		public Document(ICachePolicy cachePolicy, DataRow dataRow) : base(cachePolicy)
		{
			PopulateMembers(dataRow);
		}

		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the name of the file (attachment) including the extension
		/// </summary>
		public string Name
		{
			get	{ return name;	}
			set { SetDirty(ref name, value); }
		}

		
		/// <summary>
		/// Gets or sets the date on which the file was created
		/// </summary>
		public DateTime DateCreated
		{
			get	{ return dateCreated; }
			set	{ SetDirty(ref dateCreated, value);	}
		}

        public bool IsSharePointDocument
        {
            get { return isSharePointDocument; }
            set { isSharePointDocument = value; }
        }

        
        public Hashtable Metadata
        {
            get{
                if (metadata == null)
                {
                    metadata = new Hashtable();
                }
                return metadata;
            }
            set{metadata = value;}
        }

        public string FolderHierarchy
        {
            get{ return folderHierarchy; }
            set {folderHierarchy = value;  }
        }

        public string FilePath 
        {
            get { return filePath; }
            set { filePath = value; }
        }
		/// <summary>
		/// Gets or sets the contents of the file
		/// </summary>
		public byte[] Blob
		{
			get	
			{ 
				try
				{
					if (blob == null)
					{
                        if (isSharePointDocument)
                        {
                            DocumentLibrary documentLibrary = new DocumentLibrary();
                            blob = documentLibrary.GetFileFromSharePoint(folderHierarchy);
                        }
                        else
                        {
                            object o = Utility.DataAccess.ExecuteScalar(Utility.DataAccess.ConnectionString, "GetDocumentBlobById",
                                Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, Id));
                            if (o != DBNull.Value)
                                blob = (byte[])o;
                        }
					}

					return blob;
				}
				catch( Exception e)
				{
					Utility.ExceptionReport.WriteToEventLog ("Document.Blob: Failed to load the attachment", e, true, Utility.ExceptionReport.ReportType.Error);
					throw;
				}
			}
			set	
			{
				if (blob != null && value != null)
				{
					//the hash generated using MD5CryptoServiceProvider.ComputeHash() is only  is only 16 bytes long. 
					//This is only 16 bytes long. The byte arrays are first hashed and the 16 byte hash values are then compared for equality.
					//Note: ComputeHash() is the final operation performed on an instance of a hash object. 
					//If another hash value needs to be generated, a new instance of a hash algorithm must be created.
					byte[] original = new MD5CryptoServiceProvider().ComputeHash(blob);
					byte[] newContent = new MD5CryptoServiceProvider().ComputeHash(value);
					for (int i=0; i<16; ++i) 
						if (original[i] != newContent[i])
						{
							blob = value;
							dirty = true;
							break;
						}
				}
				else
				{
					blob = value;
					dirty = true;
				}
			}
		}

        /// <summary>
		/// Gets or sets the PDFVersion of the file
		/// </summary>
		public byte[] PDFBlob
		{
            get
            {
                try
                {
                    if (pdfBlob == null )
                    {
                        if (isSharePointDocument && this.IsConvertedToPdf)
                        {
                            folderHierarchy = Path.ChangeExtension(folderHierarchy, ".PDF");
                            DocumentLibrary documentLibrary = new DocumentLibrary();
                            try
                            {
                                pdfBlob = documentLibrary.GetFileFromSharePoint(folderHierarchy);
                            }
                            catch
                            {
                                pdfBlob = null;
                            }

                        }
                        else
                        {
                            pdfBlob = null;
                        }
                    }

                    return pdfBlob;
                }
                catch (Exception e)
                {
                    Utility.ExceptionReport.WriteToEventLog("Document.PDFBlob: Failed to load the PDF Attachment", e, true, Utility.ExceptionReport.ReportType.Error);
                    throw;
                }
            }
            set
            {
				if (pdfBlob != null && value != null)
                {
                    //the hash generated using MD5CryptoServiceProvider.ComputeHash() is only  is only 16 bytes long. 
                    //This is only 16 bytes long. The byte arrays are first hashed and the 16 byte hash values are then compared for equality.
                    //Note: ComputeHash() is the final operation performed on an instance of a hash object. 
                    //If another hash value needs to be generated, a new instance of a hash algorithm must be created.
                    byte[] original = new MD5CryptoServiceProvider().ComputeHash(pdfBlob);
                    byte[] newContent = new MD5CryptoServiceProvider().ComputeHash(value);
                    for (int i = 0; i < 16; ++i)
                        if (original[i] != newContent[i])
                        {
                            pdfBlob = value;
                            dirty = true;
                            break;
                        }
                }
                else
                {
                    pdfBlob = value;
                    dirty = true;
                }
            }
		}
		
		/// <summary>
		/// Gets or sets the deleted flag on the Document object
		/// </summary>
		public bool MarkForRemoval
		{
			get	{ return markForRemoval; }
			set	{ SetDirty(ref markForRemoval, value); }
		}

		/// <summary>
		/// Gets or sets the deleted flag on the Document object
		/// </summary>
		public bool IsConvertedToPdf
		{
			get { return isConvertedToPdf; }
			set { isConvertedToPdf = value; }
		}

      /// <summary>
      /// Returns the file extension in upper case including the ".".
      /// If an extnesion does not exist, an empty string is returned.
      /// </summary>
      public string Extension
      {
         get
         {
            string extension = Path.GetExtension(name);
            return ( null == extension ? string.Empty : extension.ToUpper() );
         }
      }

		#endregion

        object ICloneable.Clone()
        {
            return Clone();
        }

        public Document Clone()
        {
            Document clone = (Document)MemberwiseClone();
            clone.Id = 0;
            clone.Blob = Blob;
            clone.IsClone = true;
            clone.Dirty = true;
            return clone;
        }

        #region SmartBusinessObject methods
		/// <summary>
		/// Determines if the object is dirty based on whether or not atleast one of its properties have changed
		/// </summary>
		/// <returns>true - if the object is dirty, false - if not.</returns>
		public override bool IsDirty()
		{
			return dirty;
		}


		/// <summary>
		/// Loads the Document object from the database with the specified id. This method does not fetch the actual contents(blob) of the file.
		/// </summary>
		/// <param name="connectionString">Information to connect to the database</param>
		/// <param name="args">Document Id of the document to be loaded</param>
		public override void Load(string connectionString, params object[] args)
		{
			if ( args.Length != 1 )
				throw new Exception("Document Load expects documentId");

			try
			{
				DataSet documentDetails = Utility.DataAccess.GetDataSet(connectionString, "dbo.GetDocumentById", 
						Utility.DataAccess.BuildSqlParameterArray("@id" ,SqlDbType.Int, (int)args[0]));
				
				DataRowCollection rows = documentDetails.Tables[0].Rows;
				if (rows.Count > 0)
					PopulateMembers(rows[0]);
			
			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("Document.Load: Failed to load the document with the specified id", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

     
		/// <summary>
		/// Saves the instance of the Document object to the database. 
		/// The stored procedure inserts a new record if the id of the object is 0, 
		/// otherwise the procedure updates the record with the matching document id
		/// The blob is stored in the database using a seperate procedure because there 
		/// might be scenarios in which the blob was never retrieved from the database. 
		/// In such cases using only one procedure to update ProtocolDocument would 
		/// result in overriding an existing blob with null.
		/// </summary>
		/// <param name="sqlTransaction">The context in which the insert/update should be executed</param>
		protected override void SaveObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			try
			{
				// the stored procedure will determine whether to insert or update an existing Document object.
				Id = Convert.ToInt32 (DataAccess.ExecuteScalar( sqlTransaction.Connection, sqlTransaction, "SaveDocument", 
					DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, Id,
					"@name", SqlDbType.VarChar, name,
					"@markForRemoval", SqlDbType.Bit, markForRemoval )));

                if (isSharePointDocument)
                {
                    SaveFileToSharePoint();
                }
                else
                {
                    SaveFile(sqlTransaction);

                }
			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("Document.SaveObject: Failed to save the document", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

        /// <summary>
        /// Stores the blob to the database
        /// </summary>
        /// <param name="sqlTransaction">context in which the blob is inserted</param>
        public void SaveFileToSharePoint()
        {
            if (filePath == null)
            {
              clone = true;
              filePath =   WriteTemporaryFile(Path.GetExtension(folderHierarchy));
            
            }
            DocumentLibrary documentLibrary = new DocumentLibrary();
            folderHierarchy = folderHierarchy.Replace("IdPrefix", Id.ToString()) ;
            documentLibrary.SaveFileToSharePoint(folderHierarchy, filePath);
            try
            {
                documentLibrary.UpdateMetadata(folderHierarchy, metadata);
            }
            catch(Exception ex)
            {
                Utility.ExceptionReport.WriteToEventLog("Document.Update: Failed to update metadata", ex, true, Utility.ExceptionReport.ReportType.Error);

            }
        }
        /// <summary>
        /// Stores the blob to the database
        /// </summary>
        /// <param name="sqlTransaction">context in which the blob is inserted</param>
        public void SavePdfToSharePoint()
        {
                DocumentLibrary documentLibrary = new DocumentLibrary();
                documentLibrary.SaveFileToSharePoint(folderHierarchy, filePath);
        }

    
        /// <summary>
        /// Updates 'ConvertedToPdf' Flag in document table after document is converted to PDF.
        /// This flag is used for VFA, VA, Current View so that the document is not converted again on the fly.
        /// </summary>
        /// <param name="insightConnectionString"></param>
        /// <param name="docId"></param>
        public void UpdateConvertedToPdfFlag(string insightConnectionString, int docId)
        {
            SqlConnection conn =  new SqlConnection(insightConnectionString);
            conn.Open();
			DataAccess.ExecuteNonQuery(conn, "dbo.UpdateConvertedToPdfFlag",
                                       DataAccess.BuildSqlParameterArray(
                                           "@docid", SqlDbType.Int, docId,
                                           "@IsConvertedToPDF", SqlDbType.Bit, true));
            conn.Close();
        
        }

	    /// <summary>
		/// Executes the DeleteDocument stored procedure passing in the document id as the parameter
		/// </summary>
		/// <param name="sqlTransaction">The transaction context in which the SQL statement is to be executed</param>
		protected override void DeleteObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery(sqlTransaction.Connection, sqlTransaction, "DeleteDocument", 
					Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, Id));
			}
			catch( Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog ("Document.DeleteObject: Failed to delete the document", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		
		/// <summary>
		/// Cache this instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache( CacheKey(), this);
		}

		
		/// <summary>
		/// Remove this instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache( CacheKey());
		}

      /// <summary>
      /// Cache Key uniquely identifies this object within the cache.
      /// </summary>
      /// <returns>the unique string for this object.</returns>
      public override string CacheKey()
      {
         return DocumentKey;
      }
		#endregion

		#region Public methods
		/// <summary>
		/// Scans files for viruses. The name and path of the tool (a command line utility) that 
		/// scans files is fetched from the configuration file.
		/// </summary>
		/// <param name="filePath">Path of the File to scan</param>
		/// <returns>true - if clean, false - if infected</returns>
		public static bool ScanFile(string filePath)
		{
			// build arguments for the command line utility
			string commandLineArguments = @"/C ";		//   /C = closes window when command terminates; /K = keeps command window open;
			
			// turn off scanning memory and boot sector
			string virusScanArguments = "\"" + Utility.Settings.GetKeyValue(ScanToolFilePathNameKey, "") + "\"" +
										@" /nm /nb /nc " + filePath;

			Process scan = new Process();
			scan.StartInfo.FileName = "cmd";								
			scan.StartInfo.Arguments = commandLineArguments + virusScanArguments;
			// to allow grabbing results
			scan.StartInfo.RedirectStandardOutput = true;					
			scan.StartInfo.UseShellExecute = false;	
			string scanOutput = string.Empty;
			try 
			{
				int timeOut = Utility.Settings.GetKeyValue(ScanningTimeoutKey, 0);
				scan.Start();
				
				if (timeOut != 0) 
				{
					scan.WaitForExit(timeOut);
				} 
				else 
				{
					scan.WaitForExit();
				}
				if (scan.HasExited) 
				{
					scanOutput = scan.StandardOutput.ReadToEnd();
				} 
				else 
				{
					Utility.ExceptionReport.WriteToEventLog ("Document.ScanFile: Could not complete scanning file", null, false, Utility.ExceptionReport.ReportType.Error);
					throw new Exception("Document.ScanFile - Could not complete scanning file");
				}
			} 
			catch (Exception e) 
			{
				Utility.ExceptionReport.WriteToEventLog ("Document.ScanFile: Error initiating scan", e, true, Utility.ExceptionReport.ReportType.Error);
				throw new Exception("Document.ScanFile - Error initiating scan", e);
			} 
			finally 
			{
				scan.Close();
			}

			return (scanOutput.IndexOf(ScanComplete) >= 0 && scanOutput.IndexOf(NoViruses) >= 0);
		}

		/// <summary>
		/// Scan the specified file for virus if scanning is enabled. The scanning operation is conducted in a seprated process.
		/// Success or failure of the scan operation is determined by looking for a specific message (configured via the
		/// application configuration file) in the output stream.
		/// </summary>
		/// <param name="filePath">Full file system path of the file to be scanned</param>
		public static void ScanFileForVirus(string filePath)
		{
			if (enableVirusScanning)
			{
				using (Process scanner = new Process())
				{
					scanner.StartInfo.FileName = "cmd";
					scanner.StartInfo.Arguments = string.Format("/c {0} \"{1}\"", virusScanner, filePath);
					scanner.StartInfo.RedirectStandardOutput = true;
					scanner.StartInfo.UseShellExecute = false;
					scanner.Start();
				
					if (virusScannerTimeout > 0) 
						scanner.WaitForExit(virusScannerTimeout);
					else 
						scanner.WaitForExit();

					if (!scanner.HasExited) 
						throw new Exception("Failed to complete virus scan");

					string result = scanner.StandardOutput.ReadToEnd();
					if (result.IndexOf(virusScannerSuccessMessage) < 0)
						throw new Exception(result);					
				} 
			}
		}

		/// <summary>
		/// Static constructor for the Document class. Retrieve the configuration information associated with the virus scanner.
		/// The full execution string for such a scanner is generated and stored for later use. Note that paths are converted
		/// to short paths to avoid invocation problems.
		/// </summary>
		static Document()
		{
			try
			{
				string s = ConfigurationManager.AppSettings["VirusScanner.Enable"];
				if (enableVirusScanning = (s == null) ? false : Convert.ToBoolean(s))
				{
					virusScannerSuccessMessage = ConfigurationManager.AppSettings["VirusScanner.SuccessMessage"];
					virusScannerTimeout = Convert.ToInt32(ConfigurationManager.AppSettings["VirusScanner.TimeOut"]);

					using (RegistryKey key = Registry.LocalMachine.OpenSubKey(ConfigurationManager.AppSettings["VirusScanner.Location.Key"]))
					{
						string imagePath =
							Path.Combine((string)key.GetValue(ConfigurationManager.AppSettings["VirusScanner.Location.Value"]),
							ConfigurationManager.AppSettings["VirusScanner.Tool.Name"]);
						if (!File.Exists(imagePath))
							throw new Exception(string.Format("{0} does not exist", imagePath));

						StringBuilder shortPath = new StringBuilder(imagePath.Length);
						GetShortPathName(imagePath, shortPath, shortPath.Capacity);

						virusScanner = string.Format(@"{0} {1}", shortPath.ToString(),
							ConfigurationManager.AppSettings["VirusScanner.Tool.Parameters"]);
					}
				}
			}
			catch (Exception e)
			{
				System.Diagnostics.Trace.WriteLine(e.Message);
				enableVirusScanning = false;
			}
		}


		/// <summary>
		/// Stores the contents of the file(blob) to the database
		/// </summary>
		/// <param name="connection">Information to connect to the database</param>
		public void SaveFile(string connectionString)
		{
			SqlConnection connection = null;
			SqlTransaction transaction = null;
			try
			{
				connection = new SqlConnection(connectionString);
				connection.Open();
				transaction = connection.BeginTransaction( Assembly.GetExecutingAssembly().GetName().Name);

				SaveFile(transaction);

				transaction.Commit();
			}
			catch( Exception e)
			{
				if( transaction != null )
				{
					transaction.Rollback();
				}
				Utility.ExceptionReport.WriteToEventLog ("Document.SaveFile: Failed to save the attachment", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
		}

      /// <summary>
      /// Writes the blob contents to a temporary file.  If the Document file
      /// name contains an extension, the temporary file will be written
      /// with the respective extension.
      /// </summary>
      /// <returns></returns>
      public string WriteTemporaryFile(string ext)
      {
         string tempFilename = Path.GetTempFileName();
         using(FileStream fs = new FileStream(tempFilename, FileMode.Open, FileAccess.Write))
         {
            if (!clone && ext.ToUpper() == ".PDF" && null != PDFBlob )
              fs.Write(PDFBlob, 0, PDFBlob.Length);
            else
              fs.Write(Blob, 0, Blob.Length);

            fs.Close();
         }

         string extension = (ext.ToUpper() == ".PDF") ? ".PDF" : ext;
         if ( null == extension || string.Empty == extension)
         {
            return tempFilename;
         }

         string filename = 
            Path.Combine( Path.GetTempPath(), string.Format("{0}_{1}", Id, Path.GetFileNameWithoutExtension(tempFilename) + extension ));

         if ( File.Exists ( filename ) ) File.Delete ( filename );
	     
         File.Move( tempFilename, filename );

         return filename;
      }

		#endregion

		#region Private methods
		/// <summary>
		/// Populates instance fields with corresponding values from the data row
		/// </summary>
		/// <param name="dataRow">A DataRow object holding the values to be populated to the instance fields</param>
		private void PopulateMembers(DataRow dataRow)
		{
			Id = (int)dataRow[ColumnNameId];
			name = (string)dataRow[ColumnNameName];
			markForRemoval = (bool)dataRow[ColumnNameMarkForRemoval];

			if (dataRow.Table.Columns.Contains(ColumnNameIsConvertedToPdf))
				isConvertedToPdf = (bool)dataRow[ColumnNameIsConvertedToPdf];
		}
		
		
		/// <summary>
		/// Stores the blob to the database
		/// </summary>
		/// <param name="sqlTransaction">context in which the blob is inserted</param>
		private void SaveFile(SqlTransaction sqlTransaction)
		{
			if (blob!= null)
			{
				DataAccess.ExecuteNonQuery( sqlTransaction.Connection, sqlTransaction, "SaveDocumentBlob", 
					DataAccess.BuildSqlParameterArray(
					"@id", SqlDbType.Int, Id,
					"@blob", SqlDbType.Image, Blob ));
			}
		}


        /// <summary>
        /// Stores the blob to the database
        /// </summary>
        /// <param name="sqlTransaction">context in which the blob is inserted</param>
        public void SavePDFFile(string connectionString)
        {            
            if (isSharePointDocument)
            {
                SavePdfToSharePoint();
                /*Set the IsConvertedToPDF flag to true in Document table
				 * */
                UpdateConvertedToPdfFlag(connectionString,Id);

            }
            else
            {
				bool status = (pdfBlob != null);
                DataAccess.ExecuteNonQuery(connectionString, "dbo.SavePDFDocumentBlob",
                        DataAccess.BuildSqlParameterArray(
                        "@documentId", SqlDbType.Int, Id,
                        "@blob", SqlDbType.Image, PDFBlob,
                        "@status", SqlDbType.Bit, status));
            }
        }
		#endregion

	}
}
